package model.cnf;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


/**
 * Represent a CNF but don't store it in memory, it only check the number of clause and var. Every access will cause to read in the file so FileCNF are less efficient for I/O operation than MemoryCNF for example but most of the time you don't need to modify them, FileCNF use really less memory.     
 * @author stephane
 *
 */
public class FileCNF extends CNF {

	public static final int SIZE_BUFFER = 4096;
	
	private RandomAccessFile file;
	/**the line where the real CNF begin (after number of clause and var)*/
	private int begin = 1;
	
	public FileCNF(String CNFfile) throws Exception {
		
		this.CNFfile = new File(CNFfile);
		if(!this.CNFfile.isFile())
			throw new IllegalArgumentException();
		// TODO Auto-generated constructor stub
		File tmp = new File(CNFfile);
		file = new RandomAccessFile(tmp, "rw");
	
		check();
	}

	@Override
	public File export(String cnf, File directory) {
		// TODO verifier les nom et s'occuper des execption
		File tmp = null;
		try {
			tmp = new File(directory, cnf);
			tmp.createNewFile();
			
			FileInputStream read = new FileInputStream(CNFfile);
			try {
				FileOutputStream write = new FileOutputStream(tmp);
				try {
					byte[] tab = new byte[SIZE_BUFFER];
					int nbread;
					while((nbread = read.read(tab)) > 0){
						write.write(tab, 0, nbread);
					}
				} finally {
					write.close();
				}
			} finally {
				read.close();
			}
		}
		catch(Exception e){
			e.printStackTrace();
			if(tmp != null)
				tmp.delete();
			tmp = null;
		}
					
		return tmp;
	}

	public String toString(){
	/*	StringBuffer s=new StringBuffer();
		s.append("p cnf ");
		s.append(String.valueOf(declaredNumVar));
		s.append(" ");
		s.append(String.valueOf(declaredNumClause));
		s.append("\n");
		for(Clause cl : clauses){
			s.append(cl.toString());
			s.append("0\n");
		}
		return s.toString();*/
		//TODO
		return "toString a faire";
	}
	
	@Override
	public File export(File directory){
		// TODO Auto-generated method stub
		String name;
		try {
			name = File.createTempFile(PREFIX+getFileName(), SUFFIX, directory).getName();
		} catch (IOException e) {
			e.printStackTrace();
			
			return null;
		}
		return export(name, directory);
	}

	
	@Override
	public void check() throws Exception {
		// TODO Auto-generated method stub
		begin = 0;
		InputStream in = new FileInputStream(CNFfile);	
		InputStreamReader ipsr=new InputStreamReader(in);
		BufferedReader br=new BufferedReader(ipsr);
	
		String line;
		while ((line = br.readLine()) != null)
		{//lit la CNF
			begin++;
			if(line.charAt(0) == COMMENTAIRE) 
				continue;
			if(line.charAt(0) == DESCRIPTION)
			{
				Scanner sc = new Scanner(line.substring(SIZE_DESCRIPTION));
				declaredNumVar = sc.nextInt();
				declaredNumClause = sc.nextInt();
				break ;
			}
			
			System.err.println("Error in CNF file");
			System.exit(1);
		}
		
		stat = new Stat();
		stat.setNumClause(declaredNumClause);
		stat.setNumVar(declaredNumVar);
		
		if(declaredNumClause > 0)
			setOffSet(1);
	}

	@Override
	public List<Clause> getClauses() throws Exception {
		// TODO Auto-generated method stub
		
		//recuperer
		List<Clause> clauses_temp=new ArrayList<Clause>();	
		InputStream in = new FileInputStream(CNFfile);	
		InputStreamReader ipsr=new InputStreamReader(in);
		BufferedReader br=new BufferedReader(ipsr);
		String line;
		while ((line=br.readLine())!=null){
			int i;
			if(line.charAt(0)=='c') continue;
			if(line.charAt(0)=='p') continue; 
			List<Literal> c=new ArrayList<Literal>();
			Scanner sc=new Scanner(line);
			while((i=sc.nextInt())!=0){
				c.add(new Literal(i));
			}
			clauses_temp.add(new Clause(c));
		}
		br.close();
		return clauses_temp;}

	
	@Override
	public void addClause(List<Literal> cl) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void addClause(Clause cl) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public Clause getClause(int i) throws IllegalArgumentException, IOException {
		// TODO Auto-generated method stub
		setOffSet(i);
		Clause c = getNextClause();
		return c;
	}

	/**
	 * return the next clause in the file
	 * @return the clause
	 * @throws IOException if something goes wrong with the file
	 */
	public Clause getNextClause() throws IOException {
		String line = file.readLine();
		
		return new Clause(line);
	}
	
	/**
	 * set the position of the file pointer to the beginning of the "i" clause 
	 * @param i number of the clause
	 * @throws IllegalArgumentException i is to great <=> i>declaredNumClause
	 * @throws IOException problem with the cnf file
	 */
	public void setOffSet(int i) throws IllegalArgumentException, IOException{
		if(i > declaredNumClause || i <= 0)
			throw new IllegalArgumentException();
		
		file.seek(0);
		int nb = 0;
		for(nb = i + begin - 1 ; nb > 0 && file.readLine() != null ; nb--);
			
	}

	
	@Override
	public void checkStat() throws Exception {
		this.stat = new Stat(this);
	}
	
}
